package site.jlopen.kuscia.service.noderoute;


import java.net.URL;
import java.util.ArrayList;
import org.apache.commons.lang3.StringUtils;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.BatchQueryDomainRouteStatusResponse;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.CreateDomainRouteResponse;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.CreateDomainRouteResponseData;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.DeleteDomainRouteResponse;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.DomainRouteKey;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.QueryDomainRouteResponse;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.QueryDomainRouteResponseData;
import org.secretflow.v1alpha1.kusciaapi.DomainRoute.RouteStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import site.jlopen.kuscia.cons.BaseCons;
import site.jlopen.kuscia.entity.GrpcApiInfo;
import site.jlopen.kuscia.errorcode.NodeRouteErrorCode;
import site.jlopen.kuscia.exception.SdkBaseException;
import site.jlopen.kuscia.model.route.NodeRouteStatusVo;
import site.jlopen.kuscia.model.route.NodeRouteVo;
import site.jlopen.kuscia.properties.KusciaAPIProperties;
import site.jlopen.kuscia.rpc.impl.KusciaDomainRouteRpcImpl;

@Service
public class KusciaNodeRouteManager extends AbstractNodeRouteManager{
	private static Logger logger = LoggerFactory.getLogger(KusciaNodeRouteManager.class);

    private DomainRoute.TokenConfig buildTokenConfig() {
        return DomainRoute.TokenConfig.newBuilder().setTokenGenMethod("RSA-GEN").build();
    }

    private DomainRoute.RouteEndpoint buildRouteEndpoint(String netAddress) {
    	//netAddress = "http://" + netAddress;
        URL url = extractProtocolHostIP(netAddress);
        String host = url.getHost();
        int port = url.getPort();
        DomainRoute.EndpointPort.Builder builder = DomainRoute.EndpointPort.newBuilder();
        if (BaseCons.PROTOCOL_HTTPS.equals(url.getProtocol())) {
            builder.setPort(port).setName("https").setProtocol("HTTPS").setIsTLS(true).build();
        } else {
            builder.setPort(port).setName("http").setProtocol("HTTP").setIsTLS(false).build();
        }
        DomainRoute.EndpointPort endpointPort = builder.build();
        return DomainRoute.RouteEndpoint.newBuilder().setHost(host).addPorts(endpointPort).build();
    }

    private URL extractProtocolHostIP(String urlString) {
        try {
            return new URL(urlString);
        } catch (Exception e) {
            throw SdkBaseException.of(NodeRouteErrorCode.NODE_ROUTE_CREATE_ERROR, e, "address format error");
        }
    }

	@Override
	public String createDomainRoute(GrpcApiInfo apiInfo, String srcNode, String dstNode, String dstAddress) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
        DomainRoute.TokenConfig tokenConfig = buildTokenConfig();
        DomainRoute.RouteEndpoint routeEndpoint = buildRouteEndpoint(dstAddress);
        DomainRoute.CreateDomainRouteRequest request =
                DomainRoute.CreateDomainRouteRequest.newBuilder()
                .setAuthenticationType("Token")
                .setDestination(dstNode)
                .setTokenConfig(tokenConfig)
                .setEndpoint(routeEndpoint)
                .setSource(srcNode)
                .build();
		try {
			CreateDomainRouteResponse response = new KusciaDomainRouteRpcImpl(apiProperties)
					.createDomainRoute(request);
			CreateDomainRouteResponseData data = response.getData();
			logger.info("{}",response);
			return data.getName();
		} catch (Exception e) {
			logger.error("创建合作节点异常：来源{}，目标{}",srcNode, dstNode);
		}
		return null;
	}

	@Override
	public void deleteDomainRoute(GrpcApiInfo apiInfo, String srcNode, String dstNode) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
		DomainRoute.DeleteDomainRouteRequest request =
                DomainRoute.DeleteDomainRouteRequest.newBuilder().setSource(srcNode).setDestination(dstNode).build();
		try {
			DeleteDomainRouteResponse response = new KusciaDomainRouteRpcImpl(apiProperties)
					.deleteDomainRoute(request);
			logger.info("{}",response);
		} catch (Exception e) {
			logger.error("删除合作节点异常：来源{}，目标{}",srcNode, dstNode);
		}
	}

	@Override
	public NodeRouteVo queryDomainRoute(GrpcApiInfo apiInfo, String srcNodeId, String dstNodeId) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
		DomainRoute.QueryDomainRouteRequest request =
                DomainRoute.QueryDomainRouteRequest.newBuilder().setSource(srcNodeId).setDestination(dstNodeId).build();
		try {
			QueryDomainRouteResponse response = new KusciaDomainRouteRpcImpl(apiProperties)
					.queryDomainRoute(request);
			logger.error("response:{}",response);
			QueryDomainRouteResponseData data = response.getData();
			if(null == data) {
				return null;
			}
			logger.error("getStatus:{}",data.getStatus());
			if(StringUtils.isBlank(data.getStatus().getStatus())) {
				return null;
			}
			RouteStatus status = data.getStatus();
			NodeRouteStatusVo statusVo = new NodeRouteStatusVo(status.getStatus(), status.getReason());
			NodeRouteVo vo = NodeRouteVo.builder()
					.name(data.getName())
					.authenticationType(data.getAuthenticationType())
					.destination(data.getDestination())
					.source(data.getSource())
					.status(statusVo)
					.build();
			return vo;
		} catch (Exception e) {
			logger.error("查询合作节点异常：来源{}，目标{}",srcNodeId, dstNodeId);
		}
		return null;
	}

	@Override
	public void batchQueryDomainRouteStatus(GrpcApiInfo apiInfo, String srcNodeId, String dstNodeId) {
		KusciaAPIProperties apiProperties = apiInfo.convert(apiInfo);
		ArrayList<DomainRouteKey> keys = new ArrayList<DomainRoute.DomainRouteKey>();
		keys.add(domainRouteKeyBuild(srcNodeId, dstNodeId));
		DomainRoute.BatchQueryDomainRouteStatusRequest request = DomainRoute.BatchQueryDomainRouteStatusRequest.newBuilder()
                .addAllRouteKeys(keys).build();
		BatchQueryDomainRouteStatusResponse response = new KusciaDomainRouteRpcImpl(apiProperties).batchQueryDomainRouteStatus(request);
		logger.info("response:{}",response);
	}

	private DomainRoute.DomainRouteKey domainRouteKeyBuild(String srcNodeId, String dstNodeId) {
        return DomainRoute.DomainRouteKey.newBuilder().setSource(srcNodeId)
                .setDestination(dstNodeId).build();
    }
}
